package com.five.monkey.feign.consumer.ws;

import com.alibaba.fastjson.JSON;
import com.five.monkey.enums.OperateTypeEnum;
import com.five.monkey.vo.CommonVo;
import com.five.monkey.vo.GraphVo;
import com.five.monkey.vo.UserVo;
import com.five.monkey.ws.WebSocketMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author jim
 * @desc
 * @date 2021-08-15 12:20
 */
@Component
/** ServerEndpoint注解是原型设计模式 */
@ServerEndpoint(value = "/feign-consumer/{userId}")
public class WebSocketServer {

    private static Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    private static final Map<Integer, WebSocketServer> WEB_SOCKET_MAP = new ConcurrentHashMap<>();

    private static AtomicLong onlineCount = new AtomicLong(0L);

    private Integer userId;

    private Session session;

    @Autowired
    private UserServer userServer;

    @Autowired
    private GraphServer graphServer;

    /**
     * 建立连接
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId) {
        this.userId = userId;
        this.session = session;
        if (WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.remove(userId);
            WEB_SOCKET_MAP.put(userId, this);
        } else {
            WEB_SOCKET_MAP.put(userId, this);
            onlineCount.incrementAndGet();
        }
        try {
            sendMessage("连接成功");
            logger.info("WebSocket连接成功:userId={},当前在线人数:{}人", userId, onlineCount.get());
        } catch (IOException e) {
            logger.error("userId={}的用户连接成功,但通知异常", userId, e);
        }
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose() {
        if (WEB_SOCKET_MAP.containsKey(this.userId)) {
            WEB_SOCKET_MAP.remove(this.userId);
            onlineCount.decrementAndGet();
        }
        logger.info("WebSocket关闭成功:userId={},当前在线人数:{}人", this.userId, onlineCount.get());
    }

    @OnError
    public void onError(Throwable e) {
        logger.error("发生错误", e);
    }

    @OnMessage
    public void onMessage(String message) {
        logger.info("userId={},收到客户端消息:{}", this.userId, message);
        WebSocketMessage webSocketMessage = JSON.parseObject(message, WebSocketMessage.class);
        OperateTypeEnum operateType = OperateTypeEnum.match(webSocketMessage.getOperateType());
        try {
            switch (operateType) {
                case USER: {
                    CommonVo<UserVo> result = userServer.userOerate(webSocketMessage.getMessage());
                    WEB_SOCKET_MAP.get(this.userId).sendMessage(JSON.toJSONString(result));
                    break;
                }
                case GRAPH: {
                    CommonVo<GraphVo> result = graphServer.graphOperate(webSocketMessage.getMessage());
                    WEB_SOCKET_MAP.get(this.userId).sendMessage(JSON.toJSONString(result));
                    break;
                }
                default: {
                    logger.error("message中operateType类型错误,operateType={}", webSocketMessage.getOperateType());
                    WEB_SOCKET_MAP.get(this.userId).sendMessage(JSON.toJSONString(CommonVo.exception(1, "operateType类型错误")));
                }
            }
        } catch (Exception e) {

        }

    }

    /**
     * 服务端主动向客户端发送消息
     * @param message 消息内容
     * @throws IOException
     */
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
}
